package com.fram.common.redis;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import com.fram.common.util.PublicMethod;

@Service
public class RedisServiceImpl implements RedisService {

	private static final Logger LOG = LoggerFactory.getLogger(RedisServiceImpl.class);

	@Autowired
	private StringRedisTemplate redisTemplate;

	public void setDateBase(Integer datebase) {
		try {
			if (datebase == null) {
				datebase = 0;
			}
			LettuceConnectionFactory connectionFactory = (LettuceConnectionFactory) redisTemplate.getConnectionFactory();
			if (connectionFactory != null && datebase != connectionFactory.getDatabase()) {
				connectionFactory.setDatabase(datebase);
				redisTemplate.setConnectionFactory(connectionFactory);
				connectionFactory.resetConnection();
			}
		} catch (Exception e) {
			LOG.error("-redis-切换数据库异常-》{}", PublicMethod.printErrorTrace(e));
		}
	}

	@Override
	public synchronized Object get(Integer datebase, String key) {
		setDateBase(datebase);
		Object result = null;
		ValueOperations<String, String> operations = redisTemplate.opsForValue();
		result = operations.get(key);
		return result;
	}

	@Override
	public synchronized boolean set(Integer datebase, String key, String value, Integer expireTime) {
		try {
			setDateBase(datebase);
			ValueOperations<String, String> operations = redisTemplate.opsForValue();
			operations.set(key, value);
			return redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}
		return false;
	}

	@Override
	public synchronized void remove(Integer datebase, String... keys) {
		setDateBase(datebase);
		for (String key : keys) {
			remove(datebase, key);
		}
	}

	@Override
	public synchronized boolean exists(Integer datebase, final String key) {
		setDateBase(datebase);
		return redisTemplate.hasKey(key);
	}

	@Override
	public synchronized void remove(Integer datebase, String key) {
		setDateBase(datebase);
		redisTemplate.delete(key);
	}

	@Override
	public synchronized boolean setExpire(Integer datebase, String key, Integer expireTime) {
		setDateBase(datebase);
		return redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
	}

	@Override
	public synchronized Long ttl(Integer datebase, String key) {
		setDateBase(datebase);
		return redisTemplate.getExpire(key);
	}

	@Override
	public synchronized Set<String> matchKeys(Integer datebase, String pattern) {
		setDateBase(datebase);
		return redisTemplate.keys(pattern);
	}

	@Override
	public synchronized Set<String> scan(Integer datebase, String matchKey, Long count) {
		setDateBase(datebase);
		Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
			Set<String> keysTmp = new HashSet<>();
			Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder().match(matchKey).count(10000).build());
			while (cursor.hasNext()) {
				if (keysTmp.size() == count) {
					break;
				}
				keysTmp.add(new String(cursor.next()));
			}
			return keysTmp;
		});
		return keys;
	}

	@Override
	public boolean getLock(String lockId, long millisecond) {
		Boolean success = redisTemplate.opsForValue().setIfAbsent(lockId, "lock", millisecond, TimeUnit.MILLISECONDS);
		return success != null && success;
	}

	@Override
	public void releaseLock(String lockId) {
		redisTemplate.delete(lockId);
	}

}
